<?php

/**
 * 马拉松活动前段控制器
 */
class marathonWebController extends base
{
    public $redisMarathonHashKey,
           $marathonInfo,
           $userHashFiledNum,
           $hashFieldPrefix,
           $marathonId;
    
    public $encryptKey = 'AbcD$#uPG2%mjh@!';
    
    public function __construct() {
        //是否在app内置浏览器中
        if (!common::isInAppWebview()) {
            //跳转至下载地址
            common::go('http://run.hupu.com/mobile');
        }
        
        parent::__construct('show');
        //没有活动ID跳转至错误页面排除分享页
        $this->marathonId = common::request('m_id', 'G');
        $_info = common::request('_info', 'G');
        
        if (empty($this->marathonId) 
                && empty($_info)) {
            header('Location: http://run.hupu.com/mobile?r=404');
            exit;
        }

        if ($_info) { //分享页处理
            $this->shareInfo = json_decode($this->decrypt($_info, $this->encryptKey), true);
            $this->marathonId = $this->shareInfo['mid'];
        }

        $this->in_user();
        
        //未登录用户跳转至登录页
        if (!$this->uid) {
            common::go('joggers://login', true);
        }
        
        $this->userHashFiledNum = 9;
        $this->hashFieldPrefix = 'marathon_';
        $this->redisMarathonHashKey = REDIS_PREFIX . 'Marathon_Activity_' . $this->marathonId;
        $this->marathonInfo = $this->_getMarationInfo();
        $nTime = time();
 
        if ($this->marathonInfo['start_time'] > $nTime) { //活动未开始
            $this->marathonInfo['status'] = 0;
        } else if ($this->marathonInfo['start_time'] <= $nTime && $nTime < $this->marathonInfo['end_time']) { //活动正在进行
            $this->marathonInfo['status'] = 1;
        } else if ($nTime >= $this->marathonInfo['end_time']) { //活动已结束
            $this->marathonInfo['status'] = 2;
            //设置key两天后过期
            if ($this->redis->ttl($this->redisMarathonHashKey) == -1) {
                $this->redis->expire($this->redisMarathonHashKey, 86400 * 2);
            }
        } else {
            $this->marathonInfo['status'] = 0;
        }
    }
    
    /**
     * 活动首页及接受页
     */
    public function domarathonIndex() {
        if ($this->_hasInRace()) { //已经报名参赛
            common::go('/marathonWeb/marathonBegin/?m_id=' . $this->marathonId);
            exit;
        }
        
        $marathonInfo = $this->marathonInfo;
        $viewData = [
            'start_time'    => $marathonInfo['start_time'],
            'end_time'      => $marathonInfo['end_time'],
            'intruduce'     => $marathonInfo['introduce'],
            'marathon_img'  => json_decode($marathonInfo['marathon_img'], true),
            'status'        => $marathonInfo['status'],
            'miles'         => $marathonInfo['total_mileage'],
            'mid'           => $marathonInfo['id'],
            'shareUrl'      => $this->_marathonShareLink(['pageType' => 1, 'datas' => null]),
            'title'         => $marathonInfo['title']
        ];
        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathon');
    }
    
    /**
     * 活动报名页
     */
    public function domarathonEnter() {
        $marathonInfo   = $this->marathonInfo;
        
        if ($marathonInfo['status'] == 2) { //活动已结束
            common::go('/marathonWeb/marathonIndex/?m_id=' . $this->marathonId);
            exit;
        } else if ($this->_hasInRace()) { //已经报名参赛
            common::go('/marathonWeb/marathonBegin/?m_id=' . $this->marathonId);
            exit;
        }
        
        $userInfo       = $this->db->getRowTable('r_user', ['nickname', 'gender', 'birthday', 'phone'], 'uid=' . $this->uid);
        $viewData       = [
            'userInfo'  => $userInfo,
            'charge'    => $marathonInfo['charge'],
            'mid'       => $marathonInfo['id']
        ];
        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathonInfo');
    }
    
    /**
     * 参赛信息添加
     */
    public function domarathonEnterAdd() {
        $marathonInfo   = $this->marathonInfo;
        $uName          = common::request('uName', 'P');
        $uGender        = common::request('uTrueGender', 'P');
        $uBirthday      = common::request('uBirthday', 'P');
        $uPhone         = common::request('uPhone', 'P');
        $uAddress       = common::request('uAddress', 'P', null, true);
        $realName       = common::request('rName', 'P', null, true);
//        $paymentType    = common::request('payment_id', 'P');
        $dateArr        = explode('-', $uBirthday);
        $suffix         = '';
        $suffix         .= strlen($dateArr[1]) == 1 ? '0'.$dateArr[1] : $dateArr[1]; //月份
        $suffix         .= strlen($dateArr[2]) == 1 ? '0'.$dateArr[2] : $dateArr[2]; //日期
        
        //插入用户信息
        $entryArr['act_id']         = $this->marathonId;
        $entryArr['uid']            = $this->uid;
        $entryArr['address']        = $uAddress;
        $entryArr['createtime']     = time();
        $entryArr['gender']         = $uGender;
        $entryArr['phone']          = $uPhone;
        $entryArr['realname']       = $realName;
        $entryArr['racenumber']     = $this->_genarateRaceNumber($suffix);
        
        if ($marathonInfo['charge'] > 0) { //需要支付报名费
            $ret = $this->db->insertRowTable('r_activity_marathon_user', $entryArr);
            
            if ($ret) {
                //调取app订单schemal
                common::go('joggers://order/goodsDetail?atype=marathon&aid=' . $this->marathonId . '&goods_id=' . $marathonInfo['goods_id'], true);
//                $orderId    = date('dHis') . 's' . $suffix . 'm' . $this->marathonId . 'u' .$this->uid;            //跳入支付
//                $payTime    = floor(($marathonInfo['end_time'] - time()) / 60);
//
//                $orderData = [
//                    'payment_type' => 2,
//                    'order_id'     => $orderId,
//                    'price'        => $marathonInfo['charge'],
//                    'subject'      => "虎扑跑步马拉松-".$marathonInfo['title'],
//                    'uid'          => $this->uid,
//                    'body'         => '',
//                    'out_minute'   => $payTime > 30 ? 30 : $payTime,
//                    'callback_url' => "http://" . $_SERVER['HTTP_HOST'] . "/marathonWeb/marathonPayDone",
//                    'return_url'   => "http://" . $_SERVER['HTTP_HOST'] . "/marathonWeb/marathonRaceNum/?m_id=" . $this->marathonId,
//                    'show_url'     => "http://" . $_SERVER['HTTP_HOST'] . "/marathonWeb/marathonIndex/?m_id=" . $this->marathonId
//                ];
//                common::go($this->_getPayUrl($orderData));
            } else {
                common::go('/marathonWeb/marathonEnter/?m_id=' . $this->marathonId);
            }
        } else { //无需报名费
            $entryArr['is_pay']     = 1;
            $ret                    = $this->db->insertRowTable('r_activity_marathon_user', $entryArr);
            
            if ($ret) {
                $marathonInfo['joins']++;
                $this->_setMarathonInfo($marathonInfo);
                $this->_setMarathonEntryInfo();
            }
            
            common::go('/marathonWeb/marathonRaceNum/?m_id=' . $this->marathonId);
        }
    }
    
    /**
     * 支付完成异步处理地址
     */
    protected function _marathonPayDone() {     
        $entryArr['act_id']         = $this->marathonId;
        $entryArr['uid']            = $this->uid;
        $entryArr['createtime']     = time();
        $entryArr['is_pay']         = 1;

        $ret = $this->db->updateRowTable('r_activity_marathon_user', $entryArr);

        if ($ret) {
            $marathonInfo = $this->marathonInfo;
            //保存参赛用户信息
            $marathonInfo['joins']++;
            $this->_setMarathonInfo($marathonInfo);
            $this->_setMarathonEntryInfo();
        }
        
        common::go('/marathonWeb/marathonRaceNum/?m_id=' . $this->marathonId);
    }
    
    /**
     * 参赛号页
     */
    public function domarathonRaceNum() {
        $entry  = $this->_getEntryInfo();
        $marathonInfo = $this->marathonInfo;
//        $getNum = common::request('getnum', 'G'); 
//        //参赛号领取
//        if (!empty($getNum) && empty($entry['getnum'])) {
//            $entry['getnum'] = 1;
//            $this->_setMarathonEntryInfo($entry);
//        }

        $viewData = [
            'mid'           => $this->marathonId,
            'racenumber'    => $entry['racenumber'],
            'nickname'      => $entry['nickname'],
            'start_time'    => $marathonInfo['start_time'],
            'end_time'      => $marathonInfo['end_time'],
            'title'         => $marathonInfo['title'],
            'miles'         => $marathonInfo['total_mileage'],
//            'hasnum'        => empty($entry['getnum']) ? 0 : 1,
            'hasnum'        => 0,
            'shareUrl'      => $this->_marathonShareLink(['pageType' => 2, 'datas' => null])
        ];
        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathonNum');
    }
    
    /**
     * 活动开始及倒计时页
     */
    public function domarathonBegin() {
        $entry = $this->_getEntryInfo();
        $marathonInfo = $this->marathonInfo;
        
        //活动已开始并且已有跑步数据跳转至进行页
        if ($marathonInfo['status'] > 0 && $entry['mileage'] > 0) {
            common::go('/marathonWeb/marathonGoing/?m_id=' . $this->marathonId);
        }
        
        $nTime = time();
        $viewData = [
            'start_time'    => $marathonInfo['start_time'],
            'end_time'      => $marathonInfo['end_time'],
            'miles'         => $marathonInfo['total_mileage'],
            'joins'         => $marathonInfo['joins'],
            'start_days'    => $marathonInfo['status'] == 1 ? floor(($nTime - $marathonInfo['start_time']) / 86400) : 0,
            'now_time'      => $nTime,
            'status'        => $marathonInfo['status'],
            'intruduce'     => $marathonInfo['introduce'],
            'marathon_img'  => json_decode($marathonInfo['marathon_img'], true),
            'initial_joins' => $marathonInfo['initial_joins'],
            'mid'           => $marathonInfo['id']
        ];

        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathonRun');
    }
    
    /**
     * 配速信息
     */
    public function domarathonMileage(){
        $marathonInfo = $this->marathonInfo;
        $entry  = $this->_getEntryInfo();
        $partData = [];
        if (!empty($entry['partData'])) {
            $tmpData = json_decode($entry['partData'], true);
            
            foreach ($tmpData as $k => $d) {
                if ($k == 0) {
                    $partData[$k] = $d;
                } else {
                    $partData[$k] = [$partData[$k - 1][0] + $d[0], $partData[$k - 1][1] + $d[1]];
                }
            }
        }
        
        $viewData = [
            'partData'      => $partData,
            'miles'         => $entry['mileage'],
            'elapsetime'    => $entry['elapsedtime'],
            'mid'           => $marathonInfo['id']
        ];
        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathonMileage');
    }
    
    /**
     * 活动进行页
     */
    public function domarathonGoing() {
        $entry  = $this->_getEntryInfo();
        $upEntry = $entry;
        $marathonInfo = $this->marathonInfo;
        
        if (!$entry['first_did']) {
            $beginTime  = $entry['createtime'] >= $marathonInfo['start_time'] ? $entry['createtime'] : $marathonInfo['start_time'];
            $endTime    = $marathonInfo['end_time'];
            $rDatas     = $this->db->getAll(
                'select did,mileage,elapsedtime from r_data where uid=' . $this->uid . ' and addtime between ' . $beginTime. ' and ' . $endTime . ' and overSpeed=0 order by did asc'
            );
            $upEntry = $this->_updateEntryInfo($entry, $marathonInfo, $rDatas);
        } else if (!$entry['is_finish']) {
            $endTime    = $marathonInfo['end_time'];
            $rDatas     = $this->db->getAll(
                'select did,mileage,elapsedtime from r_data where did>' . $entry['last_did'] . ' and uid=' . $this->uid . ' and addtime<=' . $endTime . ' and overSpeed=0 order by did asc'
            );
            $upEntry = $this->_updateEntryInfo($entry, $marathonInfo, $rDatas);
        } else {
            
        }
        
        //用于区分是否有新的跑步记录
        if (!empty($entry['latest_mileage']) 
            && $upEntry['latest_mileage'] == $entry['latest_mileage'] 
            && ($entry['is_finish'] || $marathonInfo['status'] == 2)) {
            $upEntry['latest_mileage'] = 0;
        }
        
        //提示弹层信息
        $promptRule = json_decode($marathonInfo['prompt_rule'], true);
        empty($promptRule) && $promptRule = []; 
        

        $needPrompt = false;
        $promptStr  = '';
        $promptImg  = [];
        $trank = empty($upEntry['rank']) ? ['total' => 0, 'gender' => 0] : json_decode($upEntry['rank'], true);
        $lrank = empty($upEntry['latest_rank']) ? ['total' => 0, 'gender' => 0] : json_decode($upEntry['latest_rank'], true);
        
        foreach ($promptRule as $rk => $rv) {
            if ($rk == 'mileage') { //里程
                $tStr = '';
                $tKey = $tPrev = 0;
                
                if (!empty($upEntry['prompt']['mileage'])) {
                    $tPrev = $upEntry['prompt']['mileage'];
                }
                
                foreach ($rv as $k => $v) {
                    if ($upEntry['mileage'] >= $k && $k > $tPrev) {
                        $tStr = $v;
                        $tKey = $k;
                    }
                }
                
                if ($tStr) {
                    $promptStr .= $tStr . ',';
                    $upEntry['prompt']['mileage'] = $tKey;
                    $halfMile = round($marathonInfo['total_mileage'] / 2);
                    $promptImg['mile'] = '/static/images/medal/cup_mile-2.png';
                    
                    //奖杯图片
                    if ($halfMile < 30){
                        if ($tKey >= 30) {
                            $promptImg['mile'] = '/static/images/medal/cup_mile-3.png';
                        } else if ($tKey >= $halfMile && $tKey < 30) {
                            $promptImg['mile'] = '/static/images/medal/cup_mile-2.png';
                        } else {
                            
                        }
                    } else {
                        if ($tKey >= 30 && $tKey < $halfMile) {
                            $promptImg['mile'] = '/static/images/medal/cup_mile-3.png';
                        } else if ($tKey >= $halfMile) {
                            $promptImg['mile'] = '/static/images/medal/cup_mile-2.png';
                        } else {
                            
                        } 
                    }

                }
            } else if ($rk == 'rank') { //排名
                $tStr = '';
                $tKey = $tPrev = 0;
                $tmpRank = $trank['total'] - $lrank['total'];
                
                if (!empty($upEntry['prompt']['rank'])) {
                    $tPrev = $upEntry['prompt']['rank'];
                }
                
                
                foreach ($rv as $k => $v) {
                    if ($tmpRank >= $k && $k > $tPrev) {
                        $tStr = $v;
                        $tKey = $k;
                    }
                }
                
                if ($tStr) {;
                    $promptStr .= $tStr . ',';
                    $upEntry['prompt']['rank'] = $tKey;
                    $promptImg['rank'] = '/static/images/medal/cup_rank.png';
                }
            } else { //时长
                $tStr = '';
                $tKey = $tPrev = 0;
                $tMin = ceil($upEntry['elapsedtime'] / 60);
                
                if (!empty($upEntry['prompt']['time'])) {
                    $tPrev = $upEntry['prompt']['time'];
                }
                
                foreach ($rv as $k => $v) {
                    if ($tMin >= $k && $k > $tPrev) {
                        $tStr = $v;
                        $tKey = $k;
                    }
                }
                
                if ($tStr) {
                    $promptStr .= $tStr . ',';
                    $upEntry['prompt']['time'] = $tKey;
                    $promptImg['rank'] = '/static/images/medal/cup_mile-3.png';
                }
            }
        }
        
        if ($promptStr) {
            $needPrompt = true;
            $contArr = explode(',', $marathonInfo['copycontent']);
            $this->_setMarathonEntryInfo($upEntry, false);
            
            if (!empty($contArr)) {
                $promptStr .= $contArr[rand(0, count($contArr) - 1)] . '!';
            } else {
                $promptStr = trim($promptStr, ',') . '!';
            }
        }
        //提示弹层信息
        
         $viewData = [
            'marathon_img'  => json_decode($marathonInfo['marathon_img'], true),
            'coordinate'    => $marathonInfo['coordinate'],
            'status'        => $marathonInfo['status'],
            'miles'         => $marathonInfo['total_mileage'],
            'mapAttr'       => $marathonInfo['mapattr'],
            'routeAttr'     => json_decode($marathonInfo['routeattr'], true),
            'mid'           => $marathonInfo['id'],
            'intruduce'     => $marathonInfo['introduce'],
            'run_miles'     => $upEntry['mileage'],
            'latest_mile'   => empty($upEntry['latest_mileage']) ? 0 : $upEntry['latest_mileage'], 
            'status'        => $marathonInfo['status'],
            'is_finish'     => $upEntry['is_finish'],
            'nickname'      => $upEntry['nickname'],
            'header'        => $upEntry['header'], 
            'needPrompt'    => $needPrompt,
            'promptStr'     => $promptStr,
            'promptImg'     => $promptImg,
            'shareUrl'      => $this->_marathonShareLink(['pageType' => 3, 'datas' => ['miles' => $upEntry['mileage'], 'rank' => ($trank['total'] - $lrank['total'])]]),
            'title'         => $marathonInfo['title']
        ];
         
        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathonRuning');
    }
    
    /**
     * 证书页
     */
    public function domarathonCertificate() {
        $entry  = $this->_getEntryInfo();
        $marathonInfo = $this->marathonInfo;
        $timeHour = floor($entry['elapsedtime'] / 3600);
        $timeHour = $timeHour > 9 ? $timeHour : '0' . $timeHour;
        $timeMin  = floor(($entry['elapsedtime'] % 3600) / 60);
        $timeMin  = $timeMin > 9 ? $timeMin : '0' . $timeMin;
        $timeSec  = $entry['elapsedtime'] % 60;
        $timeSec  = $timeSec > 9 ? $timeSec : '0' . $timeSec;
        $viewData = [
            'nickname'      => $entry['nickname'],
            'raceNum'      => $entry['racenumber'],
            'genderStr'     => $entry['gender'] == 1 ? '男' : '女',
            'title'         => $marathonInfo['title'],
            'timeStr'       => $timeHour . ':' . $timeMin . ':' . $timeSec,
            'rank'          => json_decode($entry['rank'], true),
            'partData'      => !empty($entry['partData']) ? json_decode($entry['partData'], true) : [],
            'shareUrl'      => $this->_marathonShareLink(['pageType' => 4, 'datas' => null]),
            'marathon_img'  => json_decode($marathonInfo['marathon_img'], true)
        ];
        
        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathon-zs');
    }
    
    /**
     * 分享链接生成
     * @param array $params 分享链接生成参数
     * @return strig 生成的分享链接
     */
    protected function _marathonShareLink($params) {
        $pageType   = $params['pageType'];
        $uid        = $this->uid;
        $mid        = $this->marathonId;
        $datas      = $params['datas'];
        
        return 'http://' . common::host() 
                . '/marathonWeb/marathonShare/?_info=' 
                . $this->encrypt(json_encode(compact('pageType', 'uid', 'mid', 'datas')), $this->encryptKey);
    }
    
    /**
     * 分享页
     */
    public function domarathonShare() {
        $shareInfo = $this->shareInfo;
        
        if (empty($shareInfo)) {
            header('Location: http://run.hupu.com/mobile?r=404');
            exit;
        }

        $sUid   = $shareInfo['uid'];
        $sPage  = $shareInfo['pageType'];
        $sData  = $shareInfo['datas'];
        $sEntry = json_decode($this->_getMarathonEntryInfo($sUid), true);
        $sEntry = $sEntry[$sUid];
        $marathonInfo = $this->marathonInfo;
        $timeHour = floor($sEntry['elapsedtime'] / 3600);
        $timeHour = $timeHour > 9 ? $timeHour : '0' . $timeHour;
        $timeMin  = floor(($sEntry['elapsedtime'] % 3600) / 60);
        $timeMin  = $timeMin > 9 ? $timeMin : '0' . $timeMin;
        $timeSec  = $sEntry['elapsedtime'] % 60;
        $timeSec  = $timeSec > 9 ? $timeSec : '0' . $timeSec;
        $viewData = [
            'title'         => $marathonInfo['title'],
            'intruduce'     => $marathonInfo['introduce'],
            'marathon_img'  => json_decode($marathonInfo['marathon_img'], true),
            'start_time'    => $marathonInfo['start_time'],
            'end_time'      => $marathonInfo['end_time'],
            'miles'         => $marathonInfo['total_mileage'],
            'racenumber'    => $sEntry['racenumber'],
            'nickname'      => $sEntry['nickname'],
            'genderStr'     => $sEntry['gender'] == 1 ? '男' : '女',
            'timeStr'       => $timeHour . ':' . $timeMin . ':' . $timeSec,
            'rank'          => json_decode($sEntry['rank'], true),
            'partData'      => !empty($sEntry['partData']) ? json_decode($sEntry['partData'], true) : [],
            'runMiles'      => $sData['miles'],
            'runRank'       => $sData['rank'],
            'uid'           => $this->uid,
            'sUid'          => $sUid,
            'pType'         => $sPage,
            'mid'           => $this->marathonId
        ];

        $this->view->assign('viewData', $viewData);
        $this->view->display('show/marathonShare');
    }
    
    /**
     * 判断是否已报名参赛
     */
    protected function _hasInRace() {
        $entry = $this->db->getRowTable('r_activity_marathon_user', [], 'act_id=' . $this->marathonId . ' and uid=' . $this->uid);
        
        if (empty($entry)) {
            return false;
        }else if (empty($entry['is_pay'])) {
            //检验是否有支付订单且支付成功
            $ret = $this->load('order')->getOrderByCond(['id'], 'act_id=' . $this->marathonId . ' and uid=' . $this->uid . ' and act_type=2 and pay_status=20');
            
            if (empty($ret)) {
                return false; 
            } else {
                $this->_marathonPayDone();
            }
        }
        
        return true;
    }


    /**
     * 获取参赛信息
     */
    protected function _getEntryInfo() {
        $entrys = json_decode($this->_getMarathonEntryInfo(), true);
        $entry  = $entrys[$this->uid];
        
        if (empty($entry)) { //缓存数据消失
            $entry = $this->db->getRowTable('r_activity_marathon_user', [], 'act_id=' . $this->marathonId . ' and uid=' . $this->uid);
            if (empty($entry)) {
                common::go('/marathonWeb/marathonIndex/?m_id=' . $this->marathonId);
            } else {
                $this->_setMarathonEntryInfo($entry);
            }
        }
        
        return $entry;
    }


    /**
     * 更新参赛者里程数时长等信息
     * @param array $entry 参赛者信息
     * @param array $marathonInfo 活动信息
     * @param array $rDatas 参赛者跑步数据
     * @return array 更新过后的参赛者信息
     */
    protected function _updateEntryInfo($entry, $marathonInfo, $rDatas) {
 
        if (!empty($rDatas)) {
            $part = empty($entry['partData']) ? [] : json_decode($entry['partData'], true);
            $last = $subMile = 0;

            foreach ($rDatas as $data) {
                if (($entry['mileage'] += $data['mileage']) < $marathonInfo['total_mileage']) {
                    $entry['elapsedtime'] += $data['elapsedtime'];
                    $part[] = [$data['mileage'], $data['elapsedtime']];
                    $last++;
                } else {
                    $entry['is_finish'] = 1;
                    $subMile = $entry['mileage'] - $marathonInfo['total_mileage'];
                    $lastTime = $data['elapsedtime'] - ceil($data['elapsedtime'] * ($subMile / $data['mileage']));
                    $entry['elapsedtime'] += $lastTime;
                    $entry['mileage']   = $marathonInfo['total_mileage'];
                    $part[] = [$data['mileage'], $data['elapsedtime']];
                    $last++;
                    break;
                }
            }

            //最近一次跑步数据及最近一次排名、最新排名
            $entry['latest_mileage']        = empty($subMile) ? $rDatas[$last - 1]['mileage'] : $rDatas[$last - 1]['mileage'] - $subMile;
            $entry['latest_elapsedtime']    = empty($lastTime) ? $rDatas[$last - 1]['elapsedtime'] : $lastTime;
            
            if ($last == 1) {
                $entry['latest_rank'] = $entry['rank'];
            } else {
                $entry['latest_rank'] = json_encode(
                    $this->_getRankInfo(($entry['mileage'] - $entry['latest_mileage']), ($entry['elapsedtime'] - $entry['latest_elapsedtime']), $entry['gender'])
                );
            }
            
            $entry['rank'] = json_encode($this->_getRankInfo($entry['mileage'], $entry['elapsedtime'], $entry['gender']));
            $upDataArr = [
                'last_did'      => $rDatas[$last - 1]['did'],
                'mileage'       => $entry['mileage'],
                'elapsedtime'   => $entry['elapsedtime'],
                'rank'          => $entry['rank'],
                'id'            => $entry['id'],
                'is_finish'     => $entry['is_finish']
            ];
            
            if (empty($entry['first_did'])){
                $upDataArr['first_did'] = $rDatas[0]['did'];
                $entry['first_did'] = $upDataArr['first_did'];
            }
           
            $entry['last_did']  = $upDataArr['last_did'];
            $entry['partData']  = json_encode($part);
            $ret = $this->db->updateRowTable('r_activity_marathon_user', $upDataArr);
            $ret && $this->_setMarathonEntryInfo($entry);
        }
        
        return $entry;
    }
    
    /**
     * 获取活动资料
     * @return array 马拉松活动资料
     */
    protected function _getMarationInfo() {
        $marathonInfo = null;
        
        if (!$this->redis->hExists($this->redisMarathonHashKey, $this->hashFieldPrefix . $this->marathonId)){
            $data = $this->db->getRowTable('r_activity_marathon', [], 'id=' . $this->marathonId);
            
            //未查找到活动跳转至错误页
            if (empty($data)) {
                header('Location: http://run.hupu.com/mobile?r=404');
                exit;
            }
            
            $data['coordinate'] = gzuncompress($data['coordinate']);
            $marathonInfo = $data;
            $this->_setMarathonInfo($marathonInfo, false);
        } else {
            $marathonInfo = json_decode(gzuncompress($this->redis->hGet($this->redisMarathonHashKey, $this->hashFieldPrefix . $this->marathonId)), true);
        }
        
        return $marathonInfo;
    }
    
    /**
     * 更新活动资料
     * @param array $info 活动资料
     * @param boolean $upTable 是否更新表记录
     */
    protected function _setMarathonInfo($info, $upTable = true) {
        $this->redis->hSet($this->redisMarathonHashKey, $this->hashFieldPrefix . $this->marathonId, gzcompress(json_encode($info), 9));
        
        if ($upTable) {
            $info['coordinate'] = gzcompress($info['coordinate'], 9);
            $this->db->updateRowTable('r_activity_marathon', $info);
        }
    }
    
    /**
     * 获取参赛者资料
     * @param numeric $uid 用户ID
     * @return array 参赛者资料
     */
    protected function _getMarathonEntryInfo($uid = null) {
        $hField = $this->_getEntryHashFiled($uid);
        
        if (!$this->redis->hExists($this->redisMarathonHashKey, $hField)) {
            $this->_setMarathonEntryInfo([], true, $uid);
        }
        
        return gzuncompress($this->redis->hGet($this->redisMarathonHashKey, $hField));
    }

    /**
     * 设置参赛者信息 
     * @param array $entryInfo 参赛者资料
     * @param boolean $isNew 是否是新建field
     * @param numeric $uid 用户ID
     */
    protected function _setMarathonEntryInfo($entryInfo = [], $isNew = false, $uid = null) {
        $hField = $this->_getEntryHashFiled($uid);
        $cashInfo = null;

        if (empty($entryInfo)) {
            $entryInfo = $this->db->getRowTable('r_activity_marathon_user', [], 'act_id=' . $this->marathonId . ' and uid=' . $this->uid);
            //单独获取用户昵称信息
            if (empty($entryInfo['redisInfo'])) {
                $nickname  = $this->db->getRowTable('r_user', ['nickname', 'header'], 'uid=' . $this->uid);
                $entryInfo = array_merge($entryInfo, $nickname);
                unset($entryInfo['redisInfo']);
            } else {
                $tmpEntry = json_decode($entryInfo['redisInfo'], true);
                $entryInfo = $tmpEntry;
            }
            
            if ($isNew) {
                $cashInfo = json_encode([$this->uid => $entryInfo]);
            } else {
                $hValues = json_decode($this->_getMarathonEntryInfo(), true);
                $hValues[$this->uid] = $entryInfo;
                $cashInfo = json_encode($hValues);
            }
        } else {
            $hValues = json_decode($this->_getMarathonEntryInfo(), true);
            $hValues[$this->uid] = $entryInfo;
            $cashInfo = json_encode($hValues);
            $this->db->updateRowTable('r_activity_marathon_user', [ 'act_id' => $this->marathonId, 'uid' => $this->uid, 'redisInfo' => json_encode($entryInfo)]);
        }

        $this->redis->hSet($this->redisMarathonHashKey, $hField, gzcompress($cashInfo, 9));
    }
    
    /**
     * 获取参赛者hash field
     * @param numeric $uid 用户ID
     * @return string 参赛者hash field
     */
    protected function _getEntryHashFiled($uid = null) {
        empty($uid) && $uid = $this->uid;
        $hFieldSuffix = intval($this->marathonId . $uid) % $this->userHashFiledNum;
        return $this->hashFieldPrefix . 'entry_' . $hFieldSuffix;
    }
    
    /**
     * 获取参赛者排名信息
     * @param numeric $mile 参赛者已跑里程数
     * @param numeric $time 参赛者已跑时长
     * @param numeric $gender 参赛者性别
     * @return array  排名信息数组
     */
    protected function _getRankInfo($mile = 0, $time = 0, $gender = 1){
        $rankArr = [];
        $sqlAll = <<<TSQL
            SELECT count(1) from (SELECT id from r_activity_marathon_user  where act_id=$this->marathonId and uid!=$this->uid and mileage>$mile
            union SELECT id from r_activity_marathon_user  where act_id=$this->marathonId and uid!=$this->uid and mileage=$mile and elapsedtime<$time) tmp
TSQL;
        
        $sqlGender = <<<TSQL
            SELECT count(1) from (SELECT id from r_activity_marathon_user  where act_id=$this->marathonId and uid!=$this->uid and gender=$gender and mileage>$mile
            union SELECT id from r_activity_marathon_user  where act_id=$this->marathonId and uid!=$this->uid  and mileage=$mile and elapsedtime<$time and gender=$gender) tmp
TSQL;
        
        $ret = $this->db->getCol($sqlAll);
        $rankArr['total'] = ++$ret[0];
        $ret = $this->db->getCol($sqlGender);
        $rankArr['gender'] = ++$ret[0];
        
        return $rankArr;
    }

    /**
     * 参赛号生成
     * @param string $suffix 参赛号后缀
     * @param numeric $len 生成的随机字符长度
     * @return string 参赛号
     */
    protected function _genarateRaceNumber($suffix, $len = 3) {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $raceNum = '';
        
        for ( $i = 0; $i < $len; $i++ ) {   
            $raceNum .= $chars[ mt_rand(0, strlen($chars) - 1) ];  
        }  
        
        return ($raceNum . $suffix);  
    }
    
    /**
     * 生成支付链接
     * @param array $orderParams 生成支付链接的参数数组
     */
    protected function _getPayUrl($orderParams){
        $this->loadLib('payment');
        $pay = new payment();
        $res = $pay->getApi('createOrder',$orderParams);
        return $res['pay_host'] . '?' . $res['pay_str'];
    }


    /**
     * 分享链接参数加密
     * @param string $str 请求参数json字符串
     * @param string $key 密钥
     */
    public function encrypt($str, $key) {
        $r = md5($key);
        $c = 0;
        $v = "";
        $len = strlen($str);
        $l = strlen($r);
        
        for ($i = 0; $i < $len; $i++) {
            if ($c == $l) {
                $c = 0;
            }
            
            $v .= $r[$c] . (substr($str, $i, 1) ^ substr($r, $c, 1));
            $c++;
        }
        
        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($this->ed($v, $key)));
    }

    /**
     * 分享链接参数解密
     * @param string $str 请求参数json字符串加密值
     * @param string $key 密钥
     */
    public function decrypt($str, $key) {
        $str = str_replace(['-', '_'], ['+', '/'], $str);
        $mod4   = strlen($str) % 4;
        
        if ($mod4) {
            $str .= substr('====', $mod4);
        }
        
        $str = base64_decode($str);
        $str = $this->ed($str,$key);
        $v = "";
		$len = strlen($str);
		
        for ($i=0;$i<$len;$i++){
			$md5 = $str[$i];
			$i++;
			$v .= ($str[$i] ^ $md5);
        }
		
        return $v;
    }
    
    public function ed($str, $key) {
        $r = md5($key);
        $c=0;
        $v = "";
	    $len = strlen($str);
	    $l = strlen($r);
		
        for ($i=0;$i<$len;$i++) {
            if ($c==$l) {
                $c=0;
            }
            
			$v .= $str[$i] ^ $r[$c];
			$c++;
        }
		
		return $v;
    }
}

